package com.biscuit.page.basicservice.conf.initialize;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.biscuit.common.annotation.RequestWhitelist;
import com.biscuit.page.basicservice.conf.properties.RequestWhitelistProperties;
import com.biscuit.page.basicservice.utils.TextUtil;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.*;

import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;

/**
 * @author biscuit
 * @createTime 2024/5/22 15:43
 */
@Configuration
public class RequestWhitelistInitialize {

    @Bean
    public RequestWhitelistProperties initRequestWhitelistBean(ApplicationContext applicationContext) {
        RequestWhitelistProperties bean = new RequestWhitelistProperties();
        bean.setWhitelistUrlList(new ArrayList<>());

        // 获取所有被 @RequestMapping 注解标注的类
        Map<String, Object> beansWithAnnotation = applicationContext.getBeansWithAnnotation(RequestMapping.class);

        // 遍历所有被 @RequestMapping 注解标注的类
        beansWithAnnotation.values().forEach(x -> {
            // 判断当前类是否标注了 @RequestMapping 注解，没有则直接退出
            RequestMapping annotation = null;
            Class<?> clazz = null;
            for (Class<?> clz : x.getClass().getInterfaces()) {
                annotation = clz.getAnnotation(RequestMapping.class);
                clazz = clz;
                if (Objects.nonNull(clz.getAnnotation(RequestMapping.class))) {
                    break;
                }
            }
            if (Objects.isNull(annotation)) {
                return;
            }

            // 获取当前类中所有的方法
            List<Method> methodList = Arrays.asList(clazz.getMethods());

            // 获取当前类上 @RequestMapping 注解的 value 属性值，获取当前类的统一请求路径前缀
            if (CollectionUtils.isEmpty(Arrays.asList(annotation.value()))) {
                return;
            }
            AtomicReference<String> pathPrefixRef = new AtomicReference<>(annotation.value()[0]);

            // 方法不为空则开始寻找当前类中被 @RequestWhitelist 注解标注的方法
            if (CollectionUtils.isNotEmpty(methodList)) {

                // 遍历当前类中的所有方法，寻找被 @RequestWhitelist 注解标注的方法
                methodList.forEach(method -> {
                    // 当前方法上有 @RequestWhitelist 注解，开始处理统一请求路径前缀（首尾下划线处理）
                    pathPrefixRef.set(TextUtil.trimOblique(pathPrefixRef.get()));

                    // 判断当前遍历方法是否标注了 @RequestWhitelist 注解
                    if (Objects.nonNull(method.getAnnotation(RequestWhitelist.class))) {
                        StringBuilder allPath = new StringBuilder();
                        allPath.append("/").append(pathPrefixRef.get()).append("/");
                        GetMapping getMapping = method.getAnnotation(GetMapping.class);
                        PostMapping postMapping = method.getAnnotation(PostMapping.class);
                        PutMapping putMapping = method.getAnnotation(PutMapping.class);
                        DeleteMapping deleteMapping = method.getAnnotation(DeleteMapping.class);
                        RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
                        if (Objects.nonNull(getMapping)) {
                            allPath.append(TextUtil.trimOblique(getMapping.value()[0]));
                        }
                        if (Objects.nonNull(postMapping)) {
                            allPath.append(TextUtil.trimOblique(postMapping.value()[0]));
                        }
                        if (Objects.nonNull(putMapping)) {
                            allPath.append(TextUtil.trimOblique(putMapping.value()[0]));
                        }
                        if (Objects.nonNull(deleteMapping)) {
                            allPath.append(TextUtil.trimOblique(deleteMapping.value()[0]));
                        }
                        if (Objects.nonNull(requestMapping)) {
                            allPath.append(TextUtil.trimOblique(requestMapping.value()[0]));
                        }
                        bean.getWhitelistUrlList().add(TextUtil.trimPathVariableReplaceWildcard(allPath.toString()));
                    }
                });
            }
        });
        return bean;
    }

}
